/*
============================================================================
 Name        : XmlEngine.cpp
 Author      : 
 Version     :
 Copyright   : Your copyright notice
 Description : CXmlEngine implementation
============================================================================
*/

#include "XmlEngine.h"
#include "XmlEngineDebug.h"

CXmlEngine::CXmlEngine(MXmlObserver& aObserver)
	: iDepth(0), iObserver(aObserver), iElementStarted(EFalse), iIsCancelled(EFalse)
{
}

EXPORT_C CXmlEngine::~CXmlEngine()
{
}

EXPORT_C CXmlEngine* CXmlEngine::NewLC(MXmlObserver& aObserver)
{
	CXmlEngine* self = new (ELeave)CXmlEngine(aObserver);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
}

EXPORT_C CXmlEngine* CXmlEngine::NewL(MXmlObserver& aObserver)
{
	CXmlEngine* self = CXmlEngine::NewLC(aObserver);
	CleanupStack::Pop(); // self;
	return self;
}

void CXmlEngine::ConstructL()
{
	LOG_START;
}

void CXmlEngine::StartElement(const TQualified& aName, const RArray<TAttribute>& attributes)
{
	if (iCurrentName->Length() > 0)
	{
		iCurrentName->Des().Append(_L("/"));
	}

	if (aName.iPrefix.Length() > 0)
	{
		iCurrentName->Des().Append(aName.iPrefix);
		iCurrentName->Des().Append(_L(":"));
	}
	iCurrentName->Des().Append(aName.iLocalName);
	LOG1("--->: %S", iCurrentName);

	iDepth++;
	iCurrentData->Des().Zero();

	// Attributes
	iCurrentAttributes.Reset();
	for (TInt i = 0; i < attributes.Count(); ++i)
	{
		TXmlAttribute xmlAttribute;
		xmlAttribute.iName.Set(attributes[i].iName.iLocalName);
		xmlAttribute.iValue.Set(attributes[i].iValue);

		LOG2("\t\tName=%S Value=%S", &(xmlAttribute.iName), &(xmlAttribute.iValue));

		iCurrentAttributes.Insert(xmlAttribute, i);
	}

	iElementStarted = ETrue;

	// Callback
	iObserver.StartElementRead(iCurrentName->Des(), iCurrentAttributes);
}

void CXmlEngine::EndElement(const TQualified& /*aName*/)
{
	LOG1("<---: %S", iCurrentName);

	// Callback
	iObserver.EndElementRead(iCurrentName->Des(), iCurrentData->Des());

	iDepth--;
	iCurrentData->Des().Zero();

	TInt pos = iCurrentName->Des().LocateReverse('/');
	if (pos != KErrNotFound)
	{
		iCurrentName->Des().Delete(pos, iCurrentName->Des().Length() - pos);
	}

	iElementStarted = EFalse;
}

void CXmlEngine::CharacterData(const TDesC& aData)
{
	if (!iElementStarted) return;

	if (aData.Length() > 0)
	{
		iCurrentData->Des().Append(aData);
	}

	LOG1("\t[ %S ]", &aData);
}

EXPORT_C void CXmlEngine::ParseL(const TPtrC8 aBuffer, const TBool aIsFinal)
{
	//Create xml reader if not exists
	if (!iReader)
	{
		iReader = CSyParser::NewLC(TPtrC());
		iReader->SetHandler(this);
		
		iCurrentName = HBufC::NewL(256);
		iCurrentData = HBufC::NewL(2048);
	}
	
	iIsCancelled = EFalse;

	//Parse buffer
	TSyExpatStatus status = iReader->Parse(aBuffer, aIsFinal);
	if (status != EStatusOk)
	{
		//TODO: Throw an exception!!
		LOG2("Error on Line %d Column %d\n", iReader->GetCurrentLineNumber(), iReader->GetCurrentColumnNumber());
	}
	else
	{
		if (aIsFinal)
		{
			LOG("Finished parsing file\n");
			CleanupStack::PopAndDestroy(iReader);
		}
	}
}

EXPORT_C void CXmlEngine::Cancel()
{
	if (!iReader) return;
	iReader->Stop(EFalse);
}
